#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <stdarg.h>
#include "sys_log.h"

int debug_level = ERROR;
static int fd;

// 获取时间字符串
static char *get_time()
{
	static char time_buf[64];
	bzero(time_buf, sizeof(time_buf));

	static time_t t;
	t = time(NULL);

	static struct tm *cur;
	cur = localtime(&t);

	sprintf(time_buf, "%04d-%02d-%02d %02d:%02d:%02d", cur->tm_year + 1900, cur->tm_mon + 1, cur->tm_mday, cur->tm_hour, cur->tm_min, cur->tm_sec);
	return time_buf;
}

// 以当前的时间做为名字,创建log文件
int log_init()
{
	char path[128];
	time_t t;
	t = time(NULL); // 获取当前时间
	srand(t);

	struct tm *cur;
	cur = localtime(&t); // 将秒数时间进行结构化处理。

	sprintf(path, "./log/sys_%04d%02d%02d_%02d%02d%02d_%04ld.log", cur->tm_year + 1900, cur->tm_mon + 1, cur->tm_mday, cur->tm_hour, cur->tm_min, cur->tm_sec, random() % 10000);

	fd = open(path, O_WRONLY | O_CREAT, 0664); // O_CREAT 文件不存在就创建，O_TRUNC 清空文件内容
	if (fd < 0)
	{
		perror("open");
	}
	return fd;
}

//日志打印
static char buf[1024]; // 静态数组
static char debug_title[][10] = {"ERROR", "INFO", "DEBUG"};
void log_print(int type, const char *file, const char *func, const int line, const char *format, ...)
{
	bzero(buf, sizeof(buf));
	int i = 0;
	//使用sprintf将时间（get_time()返回）、日志类型（debug_title[type]）、文件名、函数名和行号拼接成基础日志信息。
	sprintf(buf, "%s [%s] %s:%s():%d ", get_time(), debug_title[type], file, func, line);
	i = strlen(buf);
	va_list args;  //定义一个可变参数列表
	va_start(args, format);  //开始对参数列表的访问

	const char *p = format;
	while (*p != '\0')
	{
		if (*p != '%')  //如果当前字符不是%（即不是一个格式说明符的开始），那么就将该字符添加到buf中，并递增i和p。
		{
			buf[i++] = *p;
			p++;
			continue;
		}
		p++;
		switch (*p)
		{
		case 'c':  //字符型
			sprintf(buf + i, "%c", (char)va_arg(args, int));
			break;
		case 'd':  //整型
			sprintf(buf + i, "%d", va_arg(args, int));
			break;
		case 's':  //字符串型
			sprintf(buf + i, "%s", va_arg(args, char *));
			break;
		case 'p':  //指针型
			sprintf(buf + i, "%p", va_arg(args, void *));
			break;
		case 'x':  //十六进制
			sprintf(buf + i, "%x", va_arg(args, int));
			break;
		default:
			break;
		}
		i = strlen(buf);  //更新i的值，确保它指向buf的末尾，sprintf会改变buf的内容。
		p++;
	}
	va_end(args);  //结束对参数列表的访问。

	//printf("%s", buf);  //将日志信息打印到标准输出。
	write(fd, buf, strlen(buf));  //将日志信息写入文件。
}

//关闭日志文件
void log_destroy(void)
{
	close(fd);
}